/////////////////////////////////////////////////////////////////////////////
//
// (c) 2007 BinaryComponents Ltd.  All Rights Reserved.
//
// http://www.binarycomponents.com/
//
/////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections;
using System.Windows.Forms;
using SuperListEx.Utility.Collections;
using System.Collections.Generic;

namespace SuperListEx.ItemLists
{
  /// <summary>
  /// Base class for implementing list storage mechanism
  /// </summary>
  public abstract class ItemList
  {
    #region vars
    private ProcessingStyle _processingStyle = ProcessingStyle.OnIdle;
    private IComparer _objectComparer = null;
    private Column[] _groupColumns;
    private ListControl _listControl;
    #endregion

    #region abstact properties
    /// <summary>
    /// Returns the count of items this list holds.
    /// </summary>
    public abstract int Count
    {
      get;
    }

    /// <summary>
    /// Returns the the item at <paramref name="index"/>
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public abstract object this[int index]
    {
      get;
    }
    #endregion

    #region internal properties
    /// <summary>
    /// Represents the grouping used when the list was created.
    /// </summary>
    internal Column[] GroupColumns
    {
      get
      {
        return _groupColumns;
      }
      set
      {
        _groupColumns = value;
      }
    }
    #endregion

    #region public abstract
    public abstract void Add(object item);
    public abstract void AddRange(IEnumerable items);
    public abstract void Remove(object item);
    public abstract void RemoveRange(IEnumerable items);
    public abstract void Clear();
    public abstract List<object> ToList();
    public abstract void ItemsChanged(params object[] items);
    public abstract int IndexOf(object o);
    public abstract void Sort();
    public abstract bool Contains(object o);
    #endregion

    #region public properties
    /// <summary>
    /// The must not return the same same sort order for any given two items otherwise otherwise after sorting 
    /// items can jump around as dotnet sort doesn't guarentee original order placement where items have the 
    /// same sort order value.
    /// </summary>
    public IComparer ObjectComparer
    {
      get
      {
        return _objectComparer;
      }
      set
      {
        _objectComparer = value;
      }
    }
    #endregion

    #region protected functions
    /// <summary>
    /// Returns the attached list control.
    /// </summary>
    protected internal ListControl ListControl
    {
      get
      {
        return _listControl;
      }
      set
      {
        if (_listControl != value)
        {
          if (_listControl != null)
          {
            _listControl.Columns.DataChanged -= Columns_DataChanged;
            DetachFromColumnsEvents(_listControl.Columns.ToArray());
          }
          _listControl = value;
          if (_listControl != null)
          {
            _listControl.Columns.DataChanged += Columns_DataChanged;
            AttachToColumnsEvents(_listControl.Columns.ToArray());
          }
        }
      }
    }
    #endregion

    #region private functions
    private void Columns_DataChanged(object sender, EventInfo<Column> e)
    {
      switch (e.EventType)
      {
        case EventType.Deleted:
          DetachFromColumnsEvents(e.Items);
          break;
        case EventType.Added:
          AttachToColumnsEvents(e.Items);
          break;
      }
    }

    private void AttachToColumnsEvents(IEnumerable<Column> columns)
    {
      foreach (Column column in columns)
      {
        column.DataChanged += column_DataChanged;
      }
    }

    private void DetachFromColumnsEvents(IEnumerable<Column> columns)
    {
      foreach (Column column in columns)
      {
        column.DataChanged -= column_DataChanged;
      }
    }

    private void column_DataChanged(object sender, ColumnDataChangedEventArgs e)
    {
      switch (e.WhatChanged)
      {
        case WhatPropertyChanged.IsGroup:
          Sort();
          break;
        case WhatPropertyChanged.IsVisible:
          if (e.Column.SortOrder != SortOrder.None)
          {
            Sort();
          }
          break;
        case WhatPropertyChanged.SortOrder:
          Sort();
          break;
      }
    }


    #endregion
  }
}